local Buff = Class(function(self, inst)
    self.inst = inst     -- 该组件主人
    self.interval = 0.1  -- 状态更新间隔
    self.buff_types = {} -- 身上存在的Buff(根据Buff类型, 仅名称)
    self.buff_tasks = {} -- 身上存在的Buff(任务相关信息)
end)

-- 是否有该种Buff, buff名称
function Buff:IsBuff(name)
    if TUNING.BUFF_FN_TYPES[name] then
        return true
    end
    return false
end

-- 身上是否有该Buff, buff名称
function Buff:HasBuff(name)
    if self.inst:HasTag("buff_" .. name) then
        return true
    end
    if HasTableKey(self.buff_tasks, name) then
        self.inst:AddTag("buff_" .. name) -- 补充Tag
        return true
    end
    return false
end

-- 获取Buff类型, buff名称
function Buff:GetBuffType(name)
    if TUNING.BUFF_FN_TYPES[name] then
        return TUNING.BUFF_FN_TYPES[name].type
    end
end

-- 获取Buff处理函数, buff名称
function Buff:GetBuffFn(name)
    if TUNING.BUFF_FN_TYPES[name] then
        return TUNING.BUFF_FN_TYPES[name].fn
    end
end

-- 获取Buff结束/失效处理函数, buff名称
function Buff:GetBuffEndFn(name)
    if TUNING.BUFF_FN_TYPES[name] then
        return TUNING.BUFF_FN_TYPES[name].end_fn
    end
end

-- 获取Buff覆盖处理方式, buff名称
function Buff:GetBuffCover(name)
    if TUNING.BUFF_FN_TYPES[name] then
        return TUNING.BUFF_FN_TYPES[name].cover
    end
end

-- 获取Buff信息, buff名称, buff信息id
function Buff:GetBuffInfo(name, id)
    local cover = self:GetBuffCover(name)
    if cover or not id then
        return self.buff_tasks[name]
    else
        if id and self.buff_tasks[name] then
            return self.buff_tasks[name][id]
        end
    end
end

-- 获取Buff叠加层数
function Buff:GetBuffLayers(name)
    local buff_info = self:GetBuffInfo(name)
    if buff_info then
        return self:GetBuffCover(name) and 1 or GetTableSize(buff_info)
    else
        return 0
    end
end

-- 添加Buff状态, buff名称, 执行间隔(s), 持续时间(s)(true持续存在), Buff执行数据, 立即执行(默认马上)
function Buff:Add(name, interval, timer, data, at_once)
    local buff_type = self:GetBuffType(name)
    local permanent = timer == true -- Buff持续存在
    timer = timer == true and "∞" or timer -- Buff持续时间
    at_once = at_once ~= false -- Buff立即执行
    local cover = self:GetBuffCover(name) -- Buff覆盖
    local id = GetRandomID() -- 可叠加Buff的Buff信息的随机ID

    if buff_type then
        if not self.buff_types[buff_type] then
            self.buff_types[buff_type] = {}
        end
        if not self.buff_types[buff_type][name] then
            self.buff_types[buff_type][name] = true
        end

        local buff_info = {
            on = true,                 -- 执行开关
            timer = timer,             -- Buff持续时间
            permanent = permanent,     -- Buff持续存在
            interval = interval,       -- Buff执行间隔
            last_interval = 0,         -- 上次执行间隔
            burial = false,            -- 执行冷却
            residue_burial = interval, -- 冷却剩余时间
            data = data or {},         -- Buff执行数据
            periodic = nil,            -- 任务对象
        }

        if cover then
            self.buff_tasks[name] = buff_info
        else
            if not self.buff_tasks[name] then
                self.buff_tasks[name] = {}
            end
            self.buff_tasks[name][id] = buff_info
        end

        self.inst:AddTag("buff_" .. name)
        self:RunInitTask(name, at_once, cover == true and id or nil)

        return id
    end
end

-- 移除Buff状态, buff名称, 根据BuffId移除(只对可叠加Buff的生效), 移除全部(只对可叠加Buff的生效)
function Buff:Remove(name, id, all)
    local cover = self:GetBuffCover(name)

    if cover or (not cover and all) then
        self.buff_tasks[name] = nil
    else
        if id and self.buff_tasks[name][id] then
            self.buff_tasks[name][id] = nil
        end
    end

    if not self.buff_tasks[name] then
        local buff_type = self:GetBuffType(name)
        if buff_type and self.buff_types[buff_type] then
            self.buff_types[buff_type][name] = nil
        end

        self.inst:RemoveTag("buff_" .. name)
    end
end

-- 初始化Buff, buff名称, BuffID(只对可叠加Buff的生效)
function Buff:RunInitBuff(name, id)
    local buff_info = self.buff_tasks[name]
    if id then
        buff_info = buff_info[id]
    end
    self:GetBuffFn(name)(self.inst, buff_info)
end

-- 执行初始Buff任务, buff名称, BuffID(只对可叠加Buff的生效)
function Buff:RunInitTask(name, at_once, id)
    if at_once then
        self:RunInitBuff(name, id) -- Buff运行
    end
    self:RunTask(name, id)         -- Buff定时任务
end

-- 执行定时Buff任务, buff名称, BuffID(只对可叠加Buff的生效)
function Buff:RunTask(name, id)
    local buff_info = self.buff_tasks[name]
    local fn = self:GetBuffFn(name)
    local end_fn = self:GetBuffEndFn(name)
    local last_interval = self.interval

    if id and buff_info[id] then
        buff_info = buff_info[id]
    end

    -- 非永久Buff刷新Buff剩余持续时间
    if not buff_info.permanent then
        buff_info.timer = buff_info.timer - buff_info.last_interval                   -- 剩余持续时间
        buff_info.residue_burial = buff_info.residue_burial - buff_info.last_interval -- 剩余冷却时间
        -- 刷新冷却
        if buff_info.residue_burial <= 0 then
            buff_info.burial = true
            buff_info.residue_burial = buff_info.interval
        end

        -- 刷新执行间隔
        if buff_info.timer > 0 then
            -- 剩余时间
            if buff_info.timer < last_interval then
                last_interval = buff_info.timer
                buff_info.last_interval = last_interval
            end
            -- 冷却时间
            if buff_info.residue_burial < last_interval then
                last_interval = buff_info.residue_burial
                buff_info.last_interval = last_interval
            end
        end
    end

    -- 冷却结束
    if buff_info.burial then
        buff_info.burial = false
        if buff_info.on then
            fn(self.inst, buff_info.data, buff_info)
        end
    end

    -- 执行下一阶段
    if buff_info.permanent or buff_info.timer > 0 then
        buff_info.periodic = self.inst:DoTaskInTime(last_interval, function()
            self:RunTask(name, id)
        end)
    else
        if end_fn then
            end_fn(self.inst, buff_info.data, buff_info)
        end
        self:Remove(name, id)
    end
end

-- Buff任务暂停, buff名称, BuffID(只对可叠加Buff的生效)
function Buff:PauseTask(name, id)
    local buff_info = self:GetBuffInfo(name)
    if buff_info then
        local cover = self:GetBuffCover(name)
        local end_fn = self:GetBuffEndFn(name)
        if cover then
            -- 覆盖型Buff
            buff_info.on = false
            if end_fn then
                end_fn(self.inst, buff_info.data, buff_info)
            end
        else
            -- 叠加型Buff
            if id and buff_info[id] then
                -- 单独Buff任务
                buff_info = buff_info[id]
                buff_info.on = false
                if end_fn then
                    end_fn(self.inst, buff_info.data, buff_info)
                end
            elseif not id then
                -- 所有Buff任务
                for _, info in pairs(buff_info) do
                    info.on = false
                    if end_fn then
                        end_fn(self.inst, info.data, info)
                    end
                end
            end
        end
    end
end

-- 恢复Buff任务, buff名称, BuffID(只对可叠加Buff的生效), 恢复时立即执行Buff(默认等冷却结束)
function Buff:ContinueTask(name, id, refresh)
    local buff_info = self:GetBuffInfo(name)
    if buff_info then
        local cover = self:GetBuffCover(name)
        local fn = self:GetBuffFn(name)
        if cover then
            -- 覆盖型Buff
            if not buff_info.on then
                buff_info.on = true
                if refresh then
                    fn(self.inst, buff_info.data, buff_info)
                end
            end
        else
            -- 叠加型Buff
            if id and buff_info[id] then
                -- 单独Buff任务
                buff_info = buff_info[id]
                if not buff_info.on then
                    buff_info.on = true
                    if refresh then
                        fn(self.inst, buff_info.data, buff_info)
                    end
                end
            elseif not id then
                -- 所有Buff任务
                for _, info in pairs(buff_info) do
                    if not info.on then
                        info.on = true
                        if refresh then
                            fn(self.inst, info.data, info)
                        end
                    end
                end
            end
        end
    end
end

-- 现有Buff状态校验
function Buff:StateVerification()
    -- 清理失效Buff
    for _, names in pairs(self.buff_types) do
        local reverse_buff_names = Reverse(names)
        local init_total = #names
        for i, name in pairs(reverse_buff_names) do
            if not self:IsBuff(name) or not HasTableKey(self.buff_tasks, name) then
                table.remove(names, init_total - i + 1)
            end
        end
    end

    -- 补充Buff
    for name, _ in pairs(self.buff_tasks) do
        local buff_delete = false
        if not self:IsBuff(name) then
            self.buff_tasks[name] = nil
            self.inst:RemoveTag("buff_" .. name)
            buff_delete = true
        end

        local buff_type = self:GetBuffType(name)
        if not buff_delete and buff_type then
            if self.buff_types[buff_type] == nil then
                self.buff_types[buff_type] = {}
            end
            if not HasTableValue(self.buff_types[buff_type], name) then
                table.insert(self.buff_types[buff_type], name)
            end
            self.inst:AddTag("buff_" .. name)
        end
    end
end

-- 存档数据保存
function Buff:OnSave()
    return {
        interval = self.interval,
        buff_types = self.buff_types,
        buff_tasks = self.buff_tasks
    }
end

-- 读档数据加载
function Buff:OnLoad(data)
    self.interval = data.interval
    self.buff_types = data.buff_types
    self.buff_tasks = data.buff_tasks

    self:StateVerification()

    for name, buff_info in pairs(self.buff_tasks) do
        local cover = self:GetBuffCover(name)
        if cover then
            self:RunInitTask(name)
        else
            for id, _ in pairs(buff_info) do
                self:RunInitTask(name, id)
            end
        end
    end
end

-- 组件卸载时执行
function Buff:OnRemoveFromEntity()
    -- 取消所有Buff的定时任务
    for name, buff_info in pairs(self.buff_tasks) do
        local cover = self:GetBuffCover(name)
        if cover then
            if buff_info.periodic and buff_info.periodic.Cancel then
                buff_info.periodic:Cancel()
            end
        else
            for _, info in pairs(buff_info) do
                if info.periodic and info.periodic.Cancel then
                    info.periodic:Cancel()
                end
            end
        end
    end
end

return Buff
